<?php

/* 
 * 微信支付
 * @author wyb
 */
class weixin {
    
    private $_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    private $_appid = ''; //应用ID
    private $_appsecret = '';
    private $_mch_id = ''; //支付商户号
    private $_data = array(); //数据集合
    private $_notify_url = 'http://wp.enfukeji.com/addons/dashen_zaoqizhuanqian/payment/wechat/notify.php';

    public function __construct( $conf ) {
		$this->_appid = $conf['appid'];
		$this->_appsecret = $conf['partnerkey'];
		$this->_mch_id = $conf['mch_id'];
        $this->_data = array(
            'appid' => $this->_appid,
            'mch_id' => $this->_mch_id,
            'nonce_str' => $this->_nonceStr(), //随机字符串
        );
    }
	
    /**
     * 手机端生成支付字符串
     * @param type $order_info
     */
    public function pay_mobile( $order_info ) {
        $this->_data['trade_type'] = 'JSAPI';
        $order_data = array(
            'body'  => $order_info['title'],
            'out_trade_no'  => $order_info['ordersn'],
            'total_fee' => 1,//(int)($order_info['fee'] * 100),
            'spbill_create_ip'  => $this->_get_client_ip(),
            'notify_url' => $order_info['notify_url'] ? $order_info['notify_url'] : $this->_notify_url,
			'openid' =>$order_info['openid']
        );
        $this->_data = array_merge( $this->_data , $order_data );
        $this->_sign();
        $result = $this->_getData();
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( !$getData || $getData['return_code'] == 'FAIL' || ($getData['return_code'] == 'SUCCESS' && $getData['result_code'] == 'FAIL') ) {
            return array( 'msg' => '支付异常，请联系客服！' , 'status' => false );
        } else {
            $new_sign = array(
                'appId' => $this->_appid,
                'timeStamp' => (string) time(),
                'nonceStr'  => $this->_nonceStr(),
                'package'  => 'prepay_id=' . $getData['prepay_id'],
				'signType' => 'MD5'
            );
            $this->_data = $new_sign;
            $this->_sign();
			$new_sign['sign'] = $this->_data['sign'];
			return $new_sign;
        }
    }
    
    /**
     * function：订单支付完成后回写数据库(微信支付回调)
     * @return json
     */
    public function notify( $getData ){
        //判断支付成功
        if( $getData['return_code'] == "SUCCESS" && $getData['result_code'] == 'SUCCESS' && $getData['appid'] == $this->_appid && $getData['mch_id'] == $this->_mch_id) {
            //签名验证
            $this->_data = $getData;
            unset( $this->_data['sign'] );
            $this->_sign();
            if( $this->_data['sign'] == $getData['sign'] ) {
                if( !$getData['out_trade_no'] ) return array('status' => 'error');
				$this->_data = array(
                    'return_code' => '<![CDATA[SUCCESS]]>',
                    'return_msg'  => '<![CDATA[OK]]>'
                );

                $out_trade_no = explode('_' , $getData['out_trade_no']);

                echo $this->_xmlData();
                return array('total_fee' => $getData['total_fee'] / 100 , 'payment_no' => $getData['transaction_id'] , 'order_sn' => $out_trade_no[0] , 'status' => 'success' );
            }
        }
        //支付失败修改订单
        
        $this->_data = array(
            'return_code' => '<![CDATA[FAIL]]>',
            'return_msg'  => '<![CDATA[error]]>'
        );
        echo $this->_xmlData();
        return array('status' => 'error');
    }

    /**
     * 生成xml
     * @return string
     */
    private function _xmlData() {
        $xml_data = "<xml>";
        foreach( $this->_data as $key => $value ) {
            $xml_data .= "<$key>$value</$key>";
        }
        $xml_data .= "</xml>";
        return $xml_data;
    }
    
    /**
     * 签名价签
     */
    private function _sign() {
        ksort( $this->_data );
        reset( $this->_data );
        $sign_data = array();
        foreach( $this->_data as $key => $value ) {
            if( $value != '' ) {
                $sign_data[] = "$key=$value";
            }
        }
        $sign_data = implode('&' , $sign_data ) . "&key=".$this->_appsecret;
        $this->_data['sign'] = strtoupper( md5( $sign_data ) );
    }
    
    /**
    * 获取客户端IP地址
    * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
    * @param boolean $adv 是否进行高级模式获取（有可能被伪装） 
    * @return mixed
    */
    private function _get_client_ip($type = 0,$adv=false) {
       $type       =  $type ? 1 : 0;
       static $ip  =   NULL;
       if ($ip !== NULL) return $ip[$type];
       if($adv){
           if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
               $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
               $pos    =   array_search('unknown',$arr);
               if(false !== $pos) unset($arr[$pos]);
               $ip     =   trim($arr[0]);
           }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
               $ip     =   $_SERVER['HTTP_CLIENT_IP'];
           }elseif (isset($_SERVER['REMOTE_ADDR'])) {
               $ip     =   $_SERVER['REMOTE_ADDR'];
           }
       }elseif (isset($_SERVER['REMOTE_ADDR'])) {
           $ip     =   $_SERVER['REMOTE_ADDR'];
       }
       // IP地址合法验证
       $long = sprintf("%u",ip2long($ip));
       $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
       return $ip[$type];
   }
   
   /**
    * 随机字符串
    */
   private function _nonceStr(){
       $str = 'ABCDEF1234567890GHIJKLMNOPQRSTUVWXYZ1234567890';
       $str_data = '';
       $strlen = strlen( $str );
       for( $i=1; $i<=32; $i++ ) {
           $str_data .= $str[rand(0,$strlen-1)];
       }
       return $str_data;
   }
   
   /**
     * 发送请求
     */
    private function _getData() {
	    $data = $this->_xmlData( $this->_data );
        $ci = curl_init();
        curl_setopt( $ci, CURLOPT_URL, $this->_url);
        curl_setopt($ci,CURLOPT_TIMEOUT, 30 );
        curl_setopt($ci,CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ci,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ci,CURLOPT_SSL_VERIFYHOST,false);
        curl_setopt( $ci, CURLOPT_HTTPHEADER, array( "Content-type: text/xml" ));
        curl_setopt( $ci, CURLOPT_POST, 1);
        curl_setopt( $ci, CURLOPT_POSTFIELDS,  $data );
        if( curl_errno( $ci ) ){
            print curl_error($ci);
        }
        $result = curl_exec( $ci );
        $status = curl_getinfo( $ci );
        curl_close($ci);
        return $result;
    }
}

